package pdfsetter.core.schema;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * This schema represents document which is composition of some other schemas. We take some document schemas and join them to one schema. Thanks to composition
 * we can set every document from set of {@link SimpleDocumentSchema}.
 * 
 * @author Andrzej Dorobisz
 */
public class CompoundDocumentSchema implements DocumentSchema {
    private final List<Iterable<PageBuildSchema>> pageBuildSchemas;
    private final int expectedNumberOfFiles;

    public CompoundDocumentSchema(List<DocumentSchema> documentSchemas) {
        pageBuildSchemas = new ArrayList<Iterable<PageBuildSchema>>(documentSchemas.size());
        int maxExpectedFileNumber = 0;
        for (DocumentSchema ds : documentSchemas) {
            pageBuildSchemas.add(ds.getPageBuildSchemas());
            maxExpectedFileNumber = Math.max(maxExpectedFileNumber, ds.getExpectedNumberOfFiles());
        }
        expectedNumberOfFiles = maxExpectedFileNumber;
    }

    @Override
    public Iterable<PageBuildSchema> getPageBuildSchemas() {
        return new Iterable<PageBuildSchema>() {

            @Override
            public Iterator<PageBuildSchema> iterator() {
                return new CompoundDocumentSchemaIterator();
            }
        };
    }

    @Override
    public int getExpectedNumberOfFiles() {
        return expectedNumberOfFiles;
    }

    private class CompoundDocumentSchemaIterator implements Iterator<PageBuildSchema> {
        private final Iterator<Iterable<PageBuildSchema>> iterableIterator;
        private Iterator<PageBuildSchema> currentSchemaIterator;
        boolean isFinished;

        private void updateCurrentIterator() {
            if (iterableIterator.hasNext())
                currentSchemaIterator = iterableIterator.next().iterator();
            else
                isFinished = true;
        }

        CompoundDocumentSchemaIterator() {
            iterableIterator = pageBuildSchemas.iterator();
            isFinished = false;
            updateCurrentIterator();
        }

        @Override
        public boolean hasNext() {
            while (!isFinished) {
                if (currentSchemaIterator.hasNext())
                    return true;
                else
                    updateCurrentIterator();
            }
            return false;
        }

        @Override
        public PageBuildSchema next() {
            if (hasNext())
                return currentSchemaIterator.next();
            else
                throw new NoSuchElementException();
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}
